package com.zd.hamster.sys;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.zd.hamster.sys.entity.FileInfo;
import com.zd.hamster.sys.util.FileUtils;
import com.zd.hamster.sys.web.Result;

@Controller
@RequestMapping("/f")
public class FileController {

	private final Logger log = LoggerFactory.getLogger(this.getClass());
	private DateTimeFormatter sufDf = DateTimeFormatter.ofPattern("yyyyMM" + File.separator + "dd");
	private DateTimeFormatter preDf = DateTimeFormatter.ofPattern("yyyyMMdd-");
	/** 默认文件分组 */
	private final static String DEFAULT_GROUP = "default";
	/** 默认临时文件路径 */
	private final static String CURR_PATH = "curr";

	/** 文件仓库路径 */
	@Value("${repository.path:}")
	private String repositoryPath;

	@PostConstruct
	public void init() {
		// 未配置仓库路径时,使用当前(jar)目录
		this.repositoryPath = StringUtils.hasText(this.repositoryPath) ? this.repositoryPath
				: FileUtils.getPath() + File.separator + "repository";
	}

	/**
	 * 上传资源
	 * 
	 * @param file
	 * @return
	 * @throws IllegalStateException
	 * @throws IOException
	 */
	@PostMapping
	@ResponseBody
	public Result upload(@RequestParam("file") MultipartFile file, FileInfo fileInfo)
			throws IllegalStateException, IOException {
		if (file.isEmpty()) {
			return Result.error();
		}
		// 获得分组
		String group = this.getGroup(fileInfo);
		// 设置文件存储目录
		LocalDate now = LocalDate.now();
		String suf = now.format(sufDf);
		// 设置返回路径
		String pre = now.format(preDf);
		String path = this.repositoryPath + File.separator + group + File.separator + suf;
		// 设置存储路径
		String uuid = UUID.randomUUID().toString();
		// 创建层级目录
		File folder = new File(path + File.separator + uuid + File.separator + CURR_PATH);
		folder.mkdirs();
		// 保存文件到磁盘
		File dest = new File(folder, file.getOriginalFilename());
		file.transferTo(dest);
		log.info("Upload - " + dest.getAbsolutePath());
		return Result.success(pre + uuid);
	}

//	@PostMapping
//	@ResponseBody
//	public String upload(@RequestParam("file") MultipartFile file, ImageFileInfo imageFileInfo) throws IllegalStateException, IOException {
//		if(!file.isEmpty()) {
//			String group = StringUtils.hasLength(imageFileInfo.getGroup()) ? imageFileInfo.getGroup() : this.defaultGroup;
//			LocalDate now = LocalDate.now();
//			String suf = now.format(sufDf);
//			File folder = new File(this.repositoryPath + File.separator + group + File.separator + suf);
//			folder.mkdirs();
//			
//			int pointIndex = file.getOriginalFilename().lastIndexOf(".");
//			String filePath = UUID.randomUUID() + (pointIndex > -1 ? file.getOriginalFilename().substring(pointIndex) : "");
//			File dest = new File(folder, filePath);
//			if (imageFileInfo.isPicscale() 
//					&& ImageUtils.isImage(file.getOriginalFilename()) 
//					&& ImageUtils.zoomScalingImage(file, dest, imageFileInfo.getMaxwidth(), imageFileInfo.getMaxheight())) {
//			} else {
//				file.transferTo(dest);
//			}
//			log.info("Upload - " + dest.getAbsolutePath());
//			String pre = now.format(preDf);
//			return pre + filePath;
//		}
//		
//		return "fail";
//	}

	/**
	 * 覆盖上传
	 * 
	 * @param file
	 * @param fileInfo
	 * @return
	 * @throws IOException
	 * @throws IllegalStateException
	 */
	@PutMapping
	@ResponseBody
	public Result cover(@RequestParam("file") MultipartFile file, FileInfo fileInfo)
			throws IllegalStateException, IOException {
		if (file.isEmpty() || !StringUtils.hasText(fileInfo.getKey())) {
			return Result.error();
		}
		String group = this.getGroup(fileInfo);
		File folder = getDecodeFile(fileInfo.getKey(), group);
		if (!folder.exists()) {
			return Result.error("原始文件不存在");
		}
		File currFolder = new File(folder, CURR_PATH);
		int childrenCount = folder.list().length;
		
		for(File oldFile : currFolder.listFiles()) {
			File versionFolder = new File(folder, String.valueOf(childrenCount));
			versionFolder.mkdirs();
			File d = new File(versionFolder, oldFile.getName());			
			oldFile.renameTo(d);
		}
		
		// 保存文件到磁盘
		File dest = new File(currFolder, file.getOriginalFilename());
		file.transferTo(dest);
		log.info("Cover - " + dest.getAbsolutePath());

		return Result.success(fileInfo.getKey());
	}

//	@ResponseBody
//	public Object commit(@PathVariable String key, String group) {
//		File source = getDecodeFile(key, tempGroup);
//		String parent = source.getParentFile().getAbsolutePath();
//		String temppath = repositoryPath + File.separator + tempGroup;
//		File tempFolder = new File(temppath);
//		String suf = parent.replace(tempFolder.getAbsolutePath(), "");
//		group = StringUtils.hasLength(group) ? group : this.defaultGroup;
//		File folder = new File(this.repositoryPath + File.separator + group + File.separator + suf);
//		folder.mkdirs();
//		File dest = new File(folder, source.getName());
//		if(source.renameTo(dest)) {
//			log.info("Move - " + dest.getAbsolutePath());
//			return new SuccessResultMessage();
//		}
//		return new ResourceDoNotExsistResultMessage();
//	}

	/**
	 * 移除资源
	 * 
	 * @param path
	 * @return
	 */
	@DeleteMapping
	@ResponseBody
	public Object remove(FileInfo fileInfo) {
		File folder = getDecodeFile(fileInfo.getKey(), fileInfo.getGroup());
		if (!folder.exists()) {
			return Result.error(404, "资源不存在");
		}
		FileSystemUtils.deleteRecursively(folder);		
		return Result.success();
	}

//	/**
//	 * 删除资源（使用用路径）
//	 * 
//	 * @param path
//	 * @return
//	 */
//	@GetMapping("/r/{path}")
//	@ResponseBody
//	public Object delete(@PathVariable String path, String group) {
//		return remove(path, group);
//	}

	/**
	 * 获取资源
	 * 
	 * @param out
	 * @param path
	 * @return
	 * @throws IOException
	 */
	@GetMapping("/{path}")
	@ResponseBody
	public Object get(HttpServletResponse response, OutputStream out, @PathVariable String path, FileInfo fileInfo)
			throws IOException {
		File folder = getDecodeFile(path, fileInfo.getGroup());		
		if (!folder.exists()) {
			return Result.error(404, "资源不存在");
		}
		String versionPath  = fileInfo.getVersion() == null ? CURR_PATH : String.valueOf(fileInfo.getVersion());
		File fileFolder = new File(folder, versionPath);
		String[] list = fileFolder.list();
		if(!fileFolder.exists() || list.length == 0) {
			return Result.error(404, "资源不存在");
		}
		File file = new File(fileFolder, list[0]);
		// response.setCharacterEncoding("UTF-8");
		// response.setHeader("Content-Type", "text/html; charset=UTF-8");
		try (FileInputStream in = new FileInputStream(file)) {
			byte[] cache = new byte[10240];
			int len = 0;
			while ((len = in.read(cache)) > 0) {
				out.write(cache, 0, len);
			}
			out.flush();
			in.close();
		}
		return null;
	}

	@PostMapping("/zip")
	@ResponseBody
	public Object downloadZipPost(HttpServletResponse response, OutputStream outputStream, String zipname,
			String[] filename, String group) {
		return this.downloadZip(response, outputStream, zipname, filename, group);
	}

	/**
	 * 打包下载(zip压缩包)
	 * 
	 * @param response
	 * @param outputStream
	 * @param uuid
	 * @return
	 */
	@RequestMapping("/zip/{zipname}")
	@ResponseBody
	public Object downloadZip(HttpServletResponse response, OutputStream outputStream, @PathVariable String zipname,
			String[] filename, String group) {
		String zipName = zipname + ".zip";
		response.addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
		response.addHeader("Content-Disposition",
				"attachment; filename=\"" + zipName + "\"; filename*=utf-8''" + zipName);
		response.addHeader("Pragma", "no-cache");
		response.addHeader("Expires", "0");

		group = StringUtils.hasLength(group) ? group : DEFAULT_GROUP;

		try (ZipOutputStream out = new ZipOutputStream(outputStream)) {
			byte[] buff = new byte[1024 * 1000];
			for (String name : filename) {
				File file = this.getDecodeFile(name, group);
				if (!file.exists()) {
					continue;
				}
				ZipEntry entry = new ZipEntry(name);
				try {
					out.putNextEntry(entry);
				} catch (IOException e) {
					e.printStackTrace();
				}
				try (FileInputStream in = new FileInputStream(file)) {
					int len;
					while ((len = in.read(buff)) > -1) {
						out.write(buff, 0, len);
					}
					in.close();
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取解析路径后的文件
	 * 
	 * @param path
	 * @return
	 */
	private File getDecodeFile(String path, String group) {
		if (path.length() < 10) {
			return new File(repositoryPath + File.separator + "nofile.html");
		}
		group = StringUtils.hasLength(group) ? group : DEFAULT_GROUP;
		String realpath = repositoryPath + File.separator + group + File.separator
				+ sufDf.format(preDf.parse(path.substring(0, 9))) + File.separator + path.substring(9);
		return new File(realpath);
	}

	/**
	 * 获取分组
	 * 
	 * @param fileInfo
	 * @return
	 */
	private String getGroup(FileInfo fileInfo) {
		String group = StringUtils.hasLength(fileInfo.getGroup()) ? fileInfo.getGroup() : DEFAULT_GROUP;
		return group;
	}

}
